package servlet;

import config.Action;
import config.ActionMapping;
import config.Forward;
import org.apache.commons.digester.Digester;
import org.apache.commons.digester.xmlrules.DigesterLoader;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * @author 石小俊
 * @date 2024年03月30日 14:49
 */
@WebServlet(urlPatterns = "*.do", loadOnStartup = 1, initParams = {
        @WebInitParam(name = "configurationLocation", value = "actions.xml")
})
public class ActionServlet extends HttpServlet {

    private ActionMapping actionMapping;
    private String configurationLocation = "actions.xml";
    private Map<String, Object> actions;

    @Override
    public void init() throws ServletException {
        actions = new HashMap<>();
        actionMapping = new ActionMapping();
        Digester digester = DigesterLoader.createDigester(ActionServlet.class.getClassLoader().getResource("config/rule.xml"));
        digester.push(actionMapping);
        try {
            String config = getInitParameter("configurationLocation");
            if (config != null) {
                configurationLocation = config;
            }
            digester.parse(ActionServlet.class.getClassLoader().getResourceAsStream(configurationLocation));
            System.out.println(actionMapping);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServletException(e.getMessage());
        }
    }

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println(actionMapping);
        // 获取用户在浏览器地址栏输入的请求
        String path = request.getServletPath();
        // 此时获取到的请求格式为:*.do
        // 但是在配置文件actions.xml中所有的请求均没有.do
        // 因此,如果想要在配置文件中找到对应的请求,则需要去除后缀.do
        path = path.substring(0, path.lastIndexOf("."));
        System.out.println("path:" + path);
        // 根据当前的请求在配置文件中找到对应的Action配置
        Action action = actionMapping.findAction(path);
        System.out.println("action:" + action);
        if (action == null) {
            throw new ServletException("在配置文件中没有找到" + path + ".do的请求");
        }
        try {
            Class actionClass = Class.forName(action.getType());
            // 先根据type在集合中查找是否存在对应的对象
            Object obj = actions.get(action.getType());
            // 如果不存在
            if (obj == null) {
                // 则说明此时尚未创建过该对象
                // 创建对应的对象
                obj = actionClass.newInstance();
                // 将创建好的对象存放到集合中,便于下次使用
                actions.put(action.getType(), obj);
            }

            // 找到Action对象之后,根据配置找到需要执行的方法
            Method method = actionClass.getMethod(action.getParameter(), HttpServletRequest.class, HttpServletResponse.class);
            // 执行对应方法,并获取方法的返回值
            String result = (String) method.invoke(obj, request, response);
            if (request == null) {
                return;
            }

            // 根据方法返回值不同找到不同的Forward配置
            Forward forward = action.findForward(result);
            if (forward == null) {
                throw new ServletException("返回值" + result + "在配置文件中没有找到对应的配置");
            }

            // 根据Forward配置中的redirect的值选择转发或者重定向
            if (forward.isRedirect()) {
                // 重定向
                response.sendRedirect(request.getContextPath() + forward.getPath());
            } else {
                // 转发
                request.getRequestDispatcher(forward.getPath()).forward(request, response);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
